package com.chukun.dubbo.spi.javassist;

import javassist.*;

/**
 * @author chukun
 * @version 1.0.0
 * @description javassist代码示例
 * @createTime 2022年01月03日 18:53:00
 *
 *   Javassist 是一个开源的分析、编辑和创建 Java 字节码的类库。 一般情况下，对字节码文
 * 件进行修改是需要使用虚拟机指令的。而使用 Javassist， 可以直接使用 java 编码的形式，而
 * 不需要了解虚拟机指令，就能动态改变类的结构，或者动态生成类。
 */
public class JavassistAction {

    public static void main(String[] args) throws Exception {
        ClassPool classPool = ClassPool.getDefault();
        // 生成class实例
        CtClass ctClass = generateClass(classPool);
        // 调用业务方法
        invokeInstance(ctClass);
    }

    /**
     * 生成class
     * @param classPool
     * @return
     * @throws Exception
     */
    private static CtClass generateClass(ClassPool classPool)throws Exception {
        // 通过ClassPool生成一个public的com.chukun.dubbo.spi.bean.Person类的ctClass
        CtClass ctClass = classPool.makeClass("com.chukun.dubbo.spi.bean.Person");

        // 对这个ctClass的初始化
        // 添加private String name;属性
        CtField nameField = new CtField(classPool.getCtClass("java.lang.String"), "name", ctClass);
        nameField.setModifiers(Modifier.PRIVATE);
        ctClass.addField(nameField);

        // 添加private int age;属性
        CtField ageField = new CtField(classPool.getCtClass("int"), "age", ctClass);
        ageField.setModifiers(Modifier.PRIVATE);
        ctClass.addField(ageField);

        // 添加getter and setter
        ctClass.addMethod(CtNewMethod.getter("getName", nameField));
        ctClass.addMethod(CtNewMethod.setter("setName", nameField));
        ctClass.addMethod(CtNewMethod.getter("getAge", ageField));
        ctClass.addMethod(CtNewMethod.setter("setAge", ageField));

        // 添加无参构造器
        CtConstructor ctConstructor = new CtConstructor(new CtClass[]{}, ctClass);
        String body = "{\nname=\"chukun\";\nage=23;\n}";
        ctConstructor.setBody(body);
        ctClass.addConstructor(ctConstructor);

        // 添加业务方法
        CtMethod ctMethod = new CtMethod(CtClass.voidType, "personInfo", new CtClass[]{}, ctClass);
        ctMethod.setModifiers(Modifier.PUBLIC);
        StringBuffer buffer = new StringBuffer();
        buffer.append("{\nSystem.out.println(\"name=\"+name);");
        buffer.append("\nSystem.out.println(\"age=\"+age);}");
        ctMethod.setBody(buffer.toString());
        ctClass.addMethod(ctMethod);
        return ctClass;
    }

    /**
     * 调用对象的方法
     * @param ctClass
     * @throws Exception
     */
    private static void invokeInstance(CtClass ctClass) throws Exception {
        // 完成真正的编译，形成字节码
        Class<?> clazz = ctClass.toClass();
        // 创建实例
        Object instance = clazz.newInstance();
        // 调用personInfo()业务方法
        instance.getClass().getMethod("personInfo", new Class[]{}).invoke(instance, new Object[]{});
    }

}
